package com.dong.es.service.impl;


import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.RequestBase;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import com.alibaba.fastjson.JSONObject;
import com.dong.es.config.EsClient;
import com.dong.es.config.EsClientPool;
import com.dong.es.config.EsProperties;
import com.dong.es.entity.EsBaseDTO;
import com.dong.es.entity.EsResult;
import com.dong.es.service.EsService;
import jakarta.json.stream.JsonGenerator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: 陈瑞东
 * @create: 2022-05-10 09:17
 */
@Service
public class EsServiceImpl implements EsService {

    @Autowired
    private EsProperties esProperties;

    private DSLWriter dslWriter = new DSLWriter();
    private Utils utils = new Utils();
    private ClassCast classCast = new ClassCast();

    @Autowired
    private EsClientPool esClientPool;



    /**
     * 公共查找方法
     * @param esBaseDTO
     * @param resultType
     * @param <T>
     * @return
     */
    public <T> EsResult<List<T>> doQueryCommon(EsBaseDTO esBaseDTO, Class<T> resultType) {
        EsResult<List<T>> result = new EsResult<>(new ArrayList<>(), 0L);

        EsClient esClient = null;
        try {
            // 获取ES客户端
            esClient = esClientPool.getClient();
            // 获取发起请求的客户端
            ElasticsearchClient client = esClient.getClient();

            // 构建查询请求
            SearchRequest searchRequest = esBaseDTO.generator().build();
            // 打印请求语句
            utils.printDSL(searchRequest);

            // 发起请求
            SearchResponse<JSONObject> search = client.search(searchRequest, JSONObject.class);

            // 转换数据格式
            List<T> list = classCast.searchHitToDOCommon(search, resultType);

            // 获取命中元数据
            HitsMetadata<JSONObject> hits = search.hits();

            // 获取查询到的总数
            long total = hits.total().value();

            // 获取聚合的数据
            Map<String, Aggregate> aggregations = search.aggregations();

            // 获取最后一个数据排序号
            List<String> sort = null;
            if (!list.isEmpty()) {
                sort = hits.hits().get(hits.hits().size() - 1).sort();
            }

            // 封装并返回数据
            return new EsResult<>(list, total, aggregations, sort);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 回收ES客户端
            esClientPool.returnClient(esClient);
        }
        return result;
    }

    /**
     * 保存 需要写ES搜索相关代码的方法 的内部类
     */
    private class DSLWriter {

    }

    /**
     * 保存 类型转换相关方法 的内部类
     */
    private class ClassCast{
        public <T> List<T> searchHitToDOCommon(SearchResponse<JSONObject> search, Class<T> resultType) {
            List<T> result = new ArrayList<>();
            if (search == null) {
                return result;
            }
            List<Hit<JSONObject>> hits = search.hits().hits();
            if (hits == null) {
                return result;
            }
            hits.forEach(hit -> {
                JSONObject jsonObject = hit.source();
                String json = JSONObject.toJSONString(jsonObject);
                T item = JSONObject.parseObject(json, resultType);
                result.add(item);
            });
            return result;
        }
    }

    /**
     * 内部工具类
     */
    private class Utils {
        /**
         * 打印 DSL 语句
         * @param request
         * @return
         */
        private void printDSL(RequestBase request) {
            if (esProperties.isPrint()) {
                String searchParams = request.toString();

                // 如果直接toString为空，则使用老方法
                if (StringUtils.isBlank(searchParams)) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    JacksonJsonpMapper mapper = new JacksonJsonpMapper();
                    JsonGenerator generator = mapper.jsonProvider().createGenerator(baos);
                    mapper.serialize(request, generator);
                    generator.close();
                    searchParams = baos.toString();
                }

                System.out.println("=====================");
                System.out.println("查询条件：");
                System.out.println(searchParams);
                System.out.println("=====================");
            }
        }
    }
}
